package br.com.tarcilahelpdesk.modelo;

import br.com.tarcilahelpdesk.enums.EnumObjetosPersistentes;
import br.com.tarcilahelpdesk.enums.EnumTipoAtributo;
import br.com.tarcilahelpdesk.persistencia.AtributoValor;
import br.com.tarcilahelpdesk.persistencia.Chamado;
import br.com.tarcilahelpdesk.persistencia.ObjetoPersistente;
import br.com.tarcilahelpdesk.persistencia.Servico;
import br.com.tarcilahelpdesk.persistencia.Solicitante;
import br.com.tarcilahelpdesk.util.DAOGenerico;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.faces.model.SelectItem;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.primefaces.model.LazyDataModel;

/**
 * Classe Modelo da arquitetura MVC.
 * @author vinicius.fonseca
 */
public class Modelo
{

    private volatile static Modelo instanciaUnica;
    private DAOGenerico dao;

    /**
     * Construtor privado para implementação do padrão Singleton.
     */
    private Modelo()
    {
    }

    /**
     * Método com padrão de projeto Singleton para fornecer somente uma instancia da classe Modelo.
     * @return instancia única da classe Modelo.
     */
    public static Modelo getInstancia()
    {
        if (instanciaUnica == null)
        {
            synchronized (Modelo.class)
            {
                if (instanciaUnica == null)
                {
                    instanciaUnica = new Modelo();
                }
            }
        }

        return instanciaUnica;
    }

    /**
     * Gera uma lista de SelectItem dos itens do EnumTipoAtributo.
     * @return Collection<SelectItem> = colecao de SelectItem.
     */
    public Collection<SelectItem> getListaTiposAtributos()
    {
        Collection<SelectItem> items = new ArrayList<SelectItem>();

        for (EnumTipoAtributo e : EnumTipoAtributo.values())
        {
            items.add(new SelectItem(e, e.name()));
        }
        return items;
    }

    /**
     * Gera uma lista de SelectItem dos itens gravados do objeto passado no argumento EnumObjetosPersistentes.
     * @param objeto = Enum do objeto.
     * @param ss = Sessao do hibernate.
     * @return SelectItem[] do objeto.
     */
    public Collection getListaObjetosPersistentes(EnumObjetosPersistentes objeto, Session ss)
    {

        if (objeto == EnumObjetosPersistentes.Solicitante)
        {
            dao = new DAOGenerico<Solicitante>(Solicitante.class);
            return dao.buscarTudoOrdenado("nome", true, ss);
        }
        if (objeto == EnumObjetosPersistentes.Servico)
        {
            dao = new DAOGenerico<Servico>(Servico.class);
            return dao.buscarTudoOrdenado("nome", true, ss);
        }
        else
        {
            return null;
        }
    }

    /**
     * Retorna a lista de atributos e valores do objeto persistente informado.
     * @param objeto 
     * @param ss 
     * @return 
     */
    public Collection<AtributoValor> getListaAtributos(ObjetoPersistente objeto, Session ss)
    {
        dao = new DAOGenerico<AtributoValor>(AtributoValor.class);
        List<Criterion> lista = new ArrayList<Criterion>();

        if (objeto instanceof Solicitante)
        {
            lista.add(Restrictions.eq("solicitante", objeto));
        }

        return dao.buscarRestrictionsProjections(lista, null, ss);
    }

    /**
     * Retorna a lista de atributos cadastrados para o ObjetoPersistente informado.
     * A lista é de somente um tipo de atributo.
     * @param objeto
     * @param ss
     * @return Collection 
     */
    public Collection getListaAtributos(EnumObjetosPersistentes objeto, Session ss)
    {
        dao = new DAOGenerico<AtributoValor>(AtributoValor.class);
        List<Criterion> lista = new ArrayList<Criterion>();
        lista.add(Restrictions.eq("objeto", objeto));
        return dao.buscarRestrictionsProjections(lista, null, ss);
    }

    /**
     * Retorna um LazyDataModel do PrimeFaces dos atributos do objeto passado em argumento.
     * @param objeto = item do EnumObjetosPersistentes
     * @param tipo 
     * @param ss = Sessao do hibernate.
     * @return LazyDataModel
     */
    public LazyDataModel gerarLazyModelAtributos(EnumObjetosPersistentes objeto, EnumTipoAtributo tipo, Session ss)
    {
        dao = new DAOGenerico<AtributoValor>(AtributoValor.class);
        List<Criterion> lista = new ArrayList<Criterion>();
        lista.add(Restrictions.eq("objeto", objeto));
        lista.add(Restrictions.eq("tipo", tipo));
        return dao.getModeloPrimeFaces(lista, null, ss);
    }

    /**
     * Retorna um LazyDataModel do PrimeFaces dos atributos do objeto passado em argumento.
     * @param objeto = item do EnumObjetosPersistentes
     * @param ss = Sessao do hibernate.
     * @return LazyDataModel
     */
    public LazyDataModel gerarLazyModelAtributos(EnumObjetosPersistentes objeto, Session ss)
    {
        dao = new DAOGenerico<AtributoValor>(AtributoValor.class);
        List<Criterion> lista = new ArrayList<Criterion>();
        lista.add(Restrictions.eq("objeto", objeto));
        return dao.getModeloPrimeFaces(lista, null, ss);
    }

    /**
     * Retorna um LazyDataModel do PrimeFaces dos registros do objeto passado em argumento.
     * @param objeto = item do EnumObjetosPersistentes
     * @param ss = Sessao do hibernate.
     * @return LazyDataModel
     */
    public LazyDataModel gerarLazyModelObjetoPersistente(EnumObjetosPersistentes objeto, Session ss)
    {

        if (objeto == EnumObjetosPersistentes.Solicitante)
        {
            dao = new DAOGenerico<Solicitante>(Solicitante.class);
            return dao.getModeloPrimeFaces(ss);
        }
        if (objeto == EnumObjetosPersistentes.Servico)
        {
            dao = new DAOGenerico<Servico>(Servico.class);
            return dao.getModeloPrimeFaces(ss);
        }
        if (objeto == EnumObjetosPersistentes.Chamado)
        {
            dao = new DAOGenerico<Chamado>(Chamado.class);
            return dao.getModeloPrimeFaces(ss);
        }
        return null;
    }

    /**
     * Adiciona um ObjetoPersistente passado em parâmetro.
     * @param objeto 
     * @param ss = Sessão do hibernate.
     */
    public void adicionar(ObjetoPersistente objeto, Session ss)
    {
        dao = new DAOGenerico<ObjetoPersistente>(ObjetoPersistente.class);
        dao.salvar(objeto, ss);
    }

    /**
     * Remove o ObjetoPersistente passado em parâmetro.
     * @param objeto 
     * @param ss = Sessão do hibernate.
     */
    public void remover(ObjetoPersistente objeto, Session ss)
    {
        dao = new DAOGenerico<ObjetoPersistente>(ObjetoPersistente.class);
        dao.remover(objeto, ss);
    }

    /**
     * Busca o ObjetoPersistente com o ID informado e tipo informado.
     * @param id
     * @param objeto 
     * @param ss
     * @return  
     */
    public ObjetoPersistente get(Long id, EnumObjetosPersistentes objeto, Session ss)
    {
        if (objeto == EnumObjetosPersistentes.Chamado)
        {
            dao = new DAOGenerico<Chamado>(Chamado.class);
            return (Chamado) dao.buscarPorID(id);
        }
        else
        {
            return null;
        }
    }
}
